home *** CD-ROM | disk | FTP | other *** search
- /***********************************************************
- Copyright 1991, 1992, 1993, 1994 by Stichting Mathematisch Centrum,
- Amsterdam, The Netherlands.
-
- All Rights Reserved
-
- Permission to use, copy, modify, and distribute this software and its
- documentation for any purpose and without fee is hereby granted,
- provided that the above copyright notice appear in all copies and that
- both that copyright notice and this permission notice appear in
- supporting documentation, and that the names of Stichting Mathematisch
- Centrum or CWI not be used in advertising or publicity pertaining to
- distribution of the software without specific, written prior permission.
-
- STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO
- THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
- FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE
- FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
- OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
- ******************************************************************/
-
- /*
- ** This module is only half-finished, really.
- ** It reads the jpeg file immedeately upon opening it, mainly because there
- ** is no official interface to the jpeg library that allows you to read
- ** the header first and the rest of the data later.
- ** Also, it does not provide any access to all sorts of jpeg parameters,
- ** like quality, etc.
- */
-
- #include "jinclude.h"
- #include <setjmp.h>
- static jmp_buf setjmp_buffer;
- static external_methods_ptr emethods;
- char jpegmsgbuf[256];
-
- /* Jpeg objects */
-
- #include "Python.h"
- #include "import.h"
-
- /* XXXX change this to the image formats we support */
-
- static PyObject *format_rgb, *format_rgb_b2t, *format_grey, *format_grey_b2t;
- extern PyObject *getimgformat(); /* Get format by name */
-
- typedef struct {
- PyObject_HEAD
- PyObject *dict; /* Attributes dictionary */
- int is_reader; /* TRUE if this is a reader */
- char *filename; /* filename of the image file */
- PyObject *data_read; /* The data being read */
- char *data_ptr; /* Where we are reading now */
- int is_grey; /* True if grey data being read */
- int rowlen; /* Length of a row */
- /* Add other (user-invisible) data here */
- } jpegobject;
-
- static PyObject *errobject;
-
- staticforward PyTypeObject Jpegtype;
-
- #define is_jpegobject(v) ((v)->ob_type == &Jpegtype)
-
- static char doc_jpeg[] = "This object reads or writes a JPEG file.\n"
- "The 'width', 'height' and 'format' attributes describe the data.\n"
- "In writer objects you can set 'quality' to a value from 0-100";
-
- /* Jpeg error handling. */
- METHODDEF void
- jpeg_trace_message (const char *msgtext)
- {
- sprintf(jpegmsgbuf, msgtext,
- emethods->message_parm[0], emethods->message_parm[1],
- emethods->message_parm[2], emethods->message_parm[3],
- emethods->message_parm[4], emethods->message_parm[5],
- emethods->message_parm[6], emethods->message_parm[7]);
- }
-
- METHODDEF void
- jpeg_error_exit (const char *msgtext)
- {
- jpeg_trace_message(msgtext); /* report the error message */
- (*emethods->free_all) (); /* clean up memory allocation & temp files */
- PyErr_SetString(errobject, jpegmsgbuf);
- longjmp(setjmp_buffer, 1); /* return control to outer routine */
- }
-
- METHODDEF void
- jpeg_my_error_exit ()
- {
- (*emethods->free_all) (); /* clean up memory allocation & temp files */
- longjmp(setjmp_buffer, 1); /* return control to outer routine */
- }
-
- /* Helper routines for the JPEG reader */
- METHODDEF void
- output_init (decompress_info_ptr cinfo)
- /* This routine should do any setup required */
- {
- PyObject *dp;
- jpegobject *self;
- int wantgrey, w, h, rowlen, size;
-
- self = (jpegobject *)cinfo->output_file;
- w = cinfo->image_width;
- h = cinfo->image_height;
- jpegsetintattr(self, "width", w);
- jpegsetintattr(self, "height", h);
- wantgrey = (cinfo->final_out_comps == 1);
- if ( wantgrey ) {
- PyDict_SetItemString(self->dict, "format", format_grey);
- PyDict_SetItemString(self->dict, "format_choices", Py_BuildValue("(O)", format_grey));
- rowlen = (w+3) & ~3;
- size = rowlen*h;
- } else {
- PyDict_SetItemString(self->dict, "format", format_rgb);
- PyDict_SetItemString(self->dict, "format_choices", Py_BuildValue("(O)", format_rgb));
- rowlen = w;
- size = rowlen*h*4;
- }
- dp = PyString_FromStringAndSize(NULL, size);
- if( PyErr_Occurred() || dp == NULL )
- jpeg_my_error_exit();
-
- self->data_read = dp;
- self->is_grey = wantgrey;
- self->data_ptr = PyString_AsString(dp);
- self->rowlen = rowlen;
- }
-
- METHODDEF void
- put_color_map (decompress_info_ptr cinfo, int num_colors, JSAMPARRAY colormap)
- /* Write the color map */
- {
- jpeg_error_exit("put_color_map called: there's a bug here somewhere!");
- }
-
- METHODDEF void
- put_pixel_rows (decompress_info_ptr cinfo, int num_rows, JSAMPIMAGE pixel_data)
- /* Write some rows of output data */
- {
- jpegobject *jp = (jpegobject *)cinfo->output_file;
- PyObject *dp = jp->data_read;
- char *greydata = jp->data_ptr;
- JSAMPROW ptr0, ptr1, ptr2;
- long col;
- int row;
- long *rgbdata;
- int r, g, b;
- int rowlen = jp->rowlen;
-
- if ( jp->is_grey ) {
- for (row=0; row < num_rows; row++) {
- ptr0 = pixel_data[0][row];
- for (col=0; col<cinfo->image_width; col++) {
- *greydata++ = GETJSAMPLE(*ptr0);
- ptr0++;
- }
- while( col < rowlen ) {
- *greydata++ = 0;
- col++;
- }
- }
- jp->data_ptr = greydata;
- } else {
- rgbdata = (long *)greydata;
- for (row=0; row < num_rows; row++) {
- ptr0 = pixel_data[0][row];
- ptr1 = pixel_data[1][row];
- ptr2 = pixel_data[2][row];
- for (col=0; col<cinfo->image_width; col++) {
- r = GETJSAMPLE(*ptr0);
- g = GETJSAMPLE(*ptr1);
- b = GETJSAMPLE(*ptr2);
- ptr0++; ptr1++; ptr2++;
- *rgbdata++ = r | (g << 8) | (b<<16);
- }
- }
- jp->data_ptr = (char *)rgbdata;
- }
- }
-
-
- METHODDEF void
- output_term (decompress_info_ptr cinfo)
- /* Finish up at the end of the output */
- {
- }
-
- METHODDEF void
- d_ui_method_selection (decompress_info_ptr cinfo)
- {
- /* if grayscale input, force grayscale output; */
- /* else leave the output colorspace as set by main routine. */
- if (cinfo->jpeg_color_space == CS_GRAYSCALE)
- cinfo->out_color_space = CS_GRAYSCALE;
-
- /* select output routines */
- cinfo->methods->output_init = output_init;
- cinfo->methods->put_color_map = put_color_map;
- cinfo->methods->put_pixel_rows = put_pixel_rows;
- cinfo->methods->output_term = output_term;
- }
-
- /* JPEG writer helper routines */
- METHODDEF void
- input_init (compress_info_ptr cinfo)
- /* Initialize for input; return image size and component data. */
- {
- }
-
- METHODDEF void
- get_input_row (compress_info_ptr cinfo, JSAMPARRAY pixel_row)
- /* Read next row of pixels into pixel_row[][] */
- {
- register FILE * infile = cinfo->input_file;
- jpegobject *self = (jpegobject *)cinfo->input_file;
- char *greydata = self->data_ptr;
- long *rgbdata;
- JSAMPROW ptr0, ptr1, ptr2;
- long col;
- long rgb;
-
- if ( self->is_grey ) {
- ptr0 = pixel_row[0];
- for (col=0; col < cinfo->image_width; col++)
- *ptr0++ = *greydata++;
- while ( col < self->rowlen ) {
- col++;
- greydata++;
- }
- self->data_ptr = greydata;
- } else {
- rgbdata = (long *)greydata;
- ptr0 = pixel_row[0];
- ptr1 = pixel_row[1];
- ptr2 = pixel_row[2];
- for (col = 0; col < cinfo->image_width; col++) {
- rgb = *rgbdata++;
- *ptr0++ = (JSAMPLE) (rgb & 0xff);
- *ptr1++ = (JSAMPLE) ((rgb>>8) & 0xff);
- *ptr2++ = (JSAMPLE) ((rgb>>16) & 0xff);
- }
- self->data_ptr = (char *)rgbdata;
- }
- }
-
-
-
- METHODDEF void
- input_term (compress_info_ptr cinfo)
- /* Finish up at the end of the input */
- {
- }
-
- METHODDEF void
- c_ui_method_selection (compress_info_ptr cinfo)
- {
- /* If the input is gray scale, generate a monochrome JPEG file. */
- if (cinfo->in_color_space == CS_GRAYSCALE)
- j_monochrome_default(cinfo);
- /* For now, always select JFIF output format. */
- jselwjfif(cinfo);
- }
-
- /* Routine to easily obtain C data from the dict python data */
- int
- jpegselfattr(self, name, fmt, ptr, wanterr)
- jpegobject *self;
- char *name;
- char *fmt;
- void *ptr;
- int wanterr;
- {
- PyObject *obj;
- char errbuf[100];
-
- obj = PyDict_GetItemString(self->dict, name);
- if ( obj == NULL ) {
- if ( wanterr ) {
- sprintf(errbuf, "Required attribute '%s' not set", name);
- PyErr_SetString(errobject, errbuf);
- return 0;
- } else {
- PyErr_Clear();
- return 0;
- }
- }
- if ( !PyArg_Parse(obj, fmt, ptr) ) {
- if ( !wanterr )
- PyErr_Clear();
- return 0;
- }
- return 1;
- }
-
- /* Routine to easily insert integer into dictionary */
- jpegsetintattr(self, name, value)
- jpegobject *self;
- char *name;
- int value;
- {
- PyObject *obj;
- int rv;
-
- obj = PyInt_FromLong(value);
- rv = PyDict_SetItemString(self->dict, name, obj);
- Py_DECREF(obj);
- return rv;
- }
-
- static jpegobject *
- newjpegobject()
- {
- jpegobject *xp;
- xp = PyObject_NEW(jpegobject, &Jpegtype);
- if (xp == NULL)
- return NULL;
- xp->dict = PyDict_New();
- xp->filename = NULL;
- xp->data_read = NULL;
- return xp;
- }
-
- static int
- initjpegreader(self, name)
- jpegobject *self;
- char *name;
- {
- char *name_copy;
- struct Decompress_info_struct cinfo;
- struct Decompress_methods_struct dc_methods;
- struct External_methods_struct e_methods;
-
- memset((char *)&cinfo, 0, sizeof cinfo);
- memset((char *)&dc_methods, 0, sizeof dc_methods);
- memset((char *)&e_methods, 0, sizeof e_methods);
- if( (name_copy=malloc(strlen(name)+1)) == NULL ) {
- PyErr_NoMemory();
- return 0;
- }
- strcpy(name_copy, name);
- self->filename = name_copy;
- self->is_reader = 1;
- if ((cinfo.input_file = fopen(name, "rb")) == NULL) {
- PyErr_SetFromErrno(PyExc_IOError);
- return 0;
- }
- cinfo.output_file = (FILE *)self;
-
- /* Initialize the system-dependent method pointers. */
- cinfo.methods = &dc_methods; /* links to method structs */
- cinfo.emethods = &e_methods;
- emethods = &e_methods; /* save struct addr for possible access */
- e_methods.error_exit = jpeg_error_exit; /* supply error-exit routine */
- e_methods.trace_message = jpeg_trace_message; /* supply trace-message routine */
- e_methods.trace_level = 0; /* default = no tracing */
- e_methods.num_warnings = 0; /* no warnings emitted yet */
- e_methods.first_warning_level = 0; /* display first corrupt-data warning */
- e_methods.more_warning_level = 3; /* but suppress additional ones */
-
- if ( setjmp(setjmp_buffer) ) {
- /* An error occurred */
- return 0;
- }
- jselmemmgr(&e_methods); /* select std memory allocation routines */
- dc_methods.d_ui_method_selection = d_ui_method_selection;
- j_d_defaults(&cinfo, TRUE);
- jselrjfif(&cinfo);
- jpeg_decompress(&cinfo);
- fclose(cinfo.input_file);
- return 1;
- }
-
- static int
- initjpegwriter(self, name)
- jpegobject *self;
- char *name;
- {
- char *name_copy;
-
- if( (name_copy=malloc(strlen(name)+1)) == NULL ) {
- PyErr_NoMemory();
- return 0;
- }
- strcpy(name_copy, name);
- self->filename = name_copy;
- self->is_reader = 0;
- PyDict_SetItemString(self->dict, "format", format_rgb);
- PyDict_SetItemString(self->dict, "format_choices",
- Py_BuildValue("(OO)", format_rgb, format_grey));
- if( PyErr_Occurred())
- return 0;
- return 1;
- }
-
- /* Jpeg methods */
-
- static void
- jpeg_dealloc(xp)
- jpegobject *xp;
- {
- Py_XDECREF(xp->dict);
- if( xp->filename )
- free(xp->filename);
- if( xp->data_read )
- Py_DECREF(xp->data_read);
- /* XXXX Free other allocated things here */
- PyMem_DEL(xp);
- }
-
- static char doc_read[] = "Return the data read by this object";
-
- static PyObject *
- jpeg_read(self, args)
- jpegobject *self;
- PyObject *args;
- {
-
- if (!PyArg_ParseTuple(args,""))
- return NULL;
- if (!self->is_reader) {
- PyErr_SetString(errobject, "Cannot read() from writer object");
- return NULL;
- }
- if (!self->data_read) {
- PyErr_SetString(errobject, "Internal error: no data read!");
- return NULL;
- }
- Py_INCREF(self->data_read);
- return self->data_read;
- }
-
- static char doc_write[] = "Write data to the JPEG file";
-
- static PyObject *
- jpeg_write(self, args)
- jpegobject *self;
- PyObject *args;
- {
- char *data;
- int datalen;
- PyObject *fmt;
- int w, h, rowlen, wantgrey, size;
- struct Compress_info_struct cinfo;
- struct Compress_methods_struct c_methods;
- struct External_methods_struct e_methods;
- int quality = 75;
-
- memset((char *)&cinfo, 0, sizeof cinfo);
- memset((char *)&c_methods, 0, sizeof c_methods);
- memset((char *)&e_methods, 0, sizeof e_methods);
-
- if (!PyArg_ParseTuple(args, "s#", &data, &datalen))
- return NULL;
- if (self->is_reader) {
- PyErr_SetString(errobject, "Cannot write() to reader object");
- return NULL;
- }
- /* XXXX Get args from self->dict and write the data */
- if ( !jpegselfattr(self, "width", "i", &w, 1) ||
- !jpegselfattr(self, "height", "i", &h, 1) ||
- !jpegselfattr(self, "format", "O", &fmt, 1) )
- return NULL;
- if ( fmt == format_rgb ) {
- rowlen = w;
- wantgrey = 0;
- size = w*h*4;
- } else {
- rowlen = (w+3) & ~3;
- wantgrey = 1;
- size = rowlen*h;
- }
- if( size != datalen ) {
- PyErr_SetString(errobject, "Incorrect datasize");
- return NULL;
- }
- (void) jpegselfattr(self, "quality", "i", &quality, 0);
-
- self->data_ptr = data;
- self->rowlen = rowlen;
- self->is_grey = wantgrey;
- /* Initialize the system-dependent method pointers. */
- if ( setjmp(setjmp_buffer) ) {
- /* An error occurred */
- return NULL;
- }
- cinfo.methods = &c_methods; /* links to method structs */
- cinfo.emethods = &e_methods;
- if ( (cinfo.output_file = fopen(self->filename, "wb")) == NULL ) {
- PyErr_SetFromErrno(PyExc_IOError);
- return NULL;
- }
- #ifdef macintosh
- setfiletype(self->filename, '????', 'JPEG');
- #endif
- emethods = &e_methods; /* save struct addr for possible access */
- e_methods.error_exit = jpeg_error_exit; /* supply error-exit routine */
- e_methods.trace_message = jpeg_trace_message; /* supply trace-message routine */
- e_methods.trace_level = 0; /* default = no tracing */
- e_methods.num_warnings = 0; /* no warnings emitted yet */
- e_methods.first_warning_level = 0; /* display first corrupt-data warning */
- e_methods.more_warning_level = 3; /* but suppress additional ones */
- jselmemmgr(&e_methods); /* select std memory allocation routines */
- c_methods.input_init = input_init;
- c_methods.get_input_row = get_input_row;
- c_methods.input_term = input_term;
- c_methods.c_ui_method_selection = c_ui_method_selection;
- j_c_defaults(&cinfo, quality, FALSE);
-
- cinfo.image_width = w; /* width in pixels */
- cinfo.image_height = h; /* height in pixels */
- cinfo.input_file = (FILE *)self;
-
- if ( wantgrey ) {
- cinfo.input_components = 1;
- cinfo.in_color_space = CS_GRAYSCALE;
- } else {
- cinfo.input_components = 3;
- cinfo.in_color_space = CS_RGB;
- }
- cinfo.data_precision = 8;
- jpeg_compress(&cinfo);
- fclose(cinfo.output_file);
- Py_INCREF(Py_None);
- return Py_None;
- }
-
- static struct PyMethodDef jpeg_methods[] = {
- {"read", (PyCFunction)jpeg_read, 1, doc_read},
- {"write", (PyCFunction)jpeg_write, 1, doc_write},
- {NULL, NULL} /* sentinel */
- };
-
- static PyObject *
- jpeg_getattr(xp, name)
- jpegobject *xp;
- char *name;
- {
- PyObject *v;
-
- if (xp->dict != NULL) {
- if ( strcmp(name, "__dict__") == 0 ) {
- Py_INCREF(xp->dict);
- return xp->dict;
- }
- if ( strcmp(name, "__doc__") == 0 ) {
- return PyString_FromString(doc_jpeg);
- }
- v = PyDict_GetItemString(xp->dict, name);
- if (v != NULL) {
- Py_INCREF(v);
- return v;
- }
- }
- return Py_FindMethod(jpeg_methods, (PyObject *)xp, name);
- }
-
- static int
- jpeg_setattr(xp, name, v)
- jpegobject *xp;
- char *name;
- PyObject *v;
- {
- if (xp->dict == NULL) {
- xp->dict = PyDict_New();
- if (xp->dict == NULL)
- return -1;
- }
- if (v == NULL) {
- int rv = PyDict_DelItemString(xp->dict, name);
- if (rv < 0)
- PyErr_SetString(PyExc_AttributeError,
- "delete non-existing imgjpeg attribute");
- return rv;
- }
- else
- return PyDict_SetItemString(xp->dict, name, v);
- }
-
- static PyTypeObject Jpegtype = {
- PyObject_HEAD_INIT(&PyType_Type)
- 0, /*ob_size*/
- "imgjpeg", /*tp_name*/
- sizeof(jpegobject), /*tp_basicsize*/
- 0, /*tp_itemsize*/
- /* methods */
- (destructor)jpeg_dealloc, /*tp_dealloc*/
- 0, /*tp_print*/
- (getattrfunc)jpeg_getattr, /*tp_getattr*/
- (setattrfunc)jpeg_setattr, /*tp_setattr*/
- 0, /*tp_compare*/
- 0, /*tp_repr*/
- 0, /*tp_as_number*/
- 0, /*tp_as_sequence*/
- 0, /*tp_as_mapping*/
- 0, /*tp_hash*/
- };
-
- static char doc_newreader[] = "Return an object that reads a JPEG file.\n"
- "Note that the actual data is read upon creation of the object.";
-
- static PyObject *
- jpeg_newreader(self, args)
- PyObject *self;
- PyObject *args;
- {
- char *filename;
- jpegobject *obj;
-
- if (!PyArg_ParseTuple(args, "s", &filename))
- return NULL;
- if ((obj = newjpegobject()) == NULL)
- return NULL;
- if ( !initjpegreader(obj, filename) ) {
- jpeg_dealloc(obj);
- return NULL;
- }
- return (PyObject *)obj;
- }
-
- static char doc_newwriter[] =
- "Return an object that creates the JPEG file passed as argument";
-
- static PyObject *
- jpeg_newwriter(self, args)
- PyObject *self;
- PyObject *args;
- {
- char *filename;
- jpegobject *obj;
-
- if (!PyArg_ParseTuple(args, "s", &filename))
- return NULL;
- if ((obj = newjpegobject()) == NULL)
- return NULL;
- if ( !initjpegwriter(obj, filename) ) {
- jpeg_dealloc(obj);
- return NULL;
- }
- return (PyObject *)obj;
- }
-
-
- /* List of functions defined in the module */
-
- static struct PyMethodDef jpeg_module_methods[] = {
- {"reader", jpeg_newreader, 1, doc_newreader},
- {"writer", jpeg_newwriter, 1, doc_newwriter},
- {NULL, NULL} /* sentinel */
- };
-
-
- /* Initialization function for the module (*must* be called initimgjpeg) */
- static char doc_imgjpeg[] =
- "Module that reads and writes JPEG image files";
-
- void
- initimgjpeg()
- {
- PyObject *m, *d, *x, *formatmodule, *formatdict;
-
- /* Create the module and add the functions */
- m = Py_InitModule("imgjpeg", jpeg_module_methods);
-
- /* Add some symbolic constants to the module */
- d = PyModule_GetDict(m);
- errobject = PyString_FromString("imgjpeg.error");
- PyDict_SetItemString(d, "error", errobject);
- x = PyString_FromString(doc_imgjpeg);
- PyDict_SetItemString(d, "__doc__", x);
-
- /* Get supported formats */
- if ((formatmodule = PyImport_ImportModule("imgformat")) == NULL)
- Py_FatalError("imgjpeg depends on imgformat");
- if ((formatdict = PyModule_GetDict(formatmodule)) == NULL)
- Py_FatalError("imgformat has no dict");
-
- format_rgb = PyDict_GetItemString(formatdict,"rgb");
- format_rgb_b2t = PyDict_GetItemString(formatdict,"rgb_b2t");
- format_grey = PyDict_GetItemString(formatdict, "grey");
- format_grey_b2t = PyDict_GetItemString(formatdict, "grey_b2t");
-
- /* Check for errors */
- if (PyErr_Occurred())
- Py_FatalError("can't initialize module imgjpeg");
- }
-